﻿using System;

using DrawingPoint = System.Drawing.Point;

namespace Model01.Objects
{
    /// <summary>
    /// Represents an odrered pair of integer x- and y- coordinates that defines a point in a two-dimensional plane.
    /// </summary>
    public class Point
    {
        #region Fields

        private int x;
        private int y;

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x">X coordinate of the point.</param>
        /// <param name="y">Y coordinate of the point.</param>
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        #region Events

        /// <summary>
        /// Event occurs when X changing.
        /// </summary>
        public event OnXChangeEvent OnXChange = delegate { };

        /// <summary>
        /// Event occurs when Y changing.
        /// </summary>
        public event OnYChangeEvent OnYChange = delegate { };

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets X coordinate of the point.
        /// </summary>
        public int X
        {
            get { return x; }
            set 
            {
                int oldX = x;
                x = value;
                OnXChange(this, new XChangeEventArgs(x - oldX)); 
            }
        }

        /// <summary>
        /// Gets or sets Y coordinate of the point.
        /// </summary>
        public int Y
        {
            get { return y; }
            set
            {
                int oldY = y;
                y = value;
                OnYChange(this, new YChangeEventArgs(y - oldY));
            }
        }

        #endregion

        #region Implicit operators

        /// <summary>
        /// User-defined conversion from Model01.Objects.Point to System.Drawing.Point.
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns> 
        public static implicit operator DrawingPoint(Point point)
        {
            return new DrawingPoint(point.X, point.Y);
        }

        /// <summary>
        /// User-defined conversion from System.Drawing.Point to Model01.Objects.Point
        /// </summary>
        /// <param name="drawPoint"></param>
        /// <returns></returns>
        public static implicit operator Point(DrawingPoint drawingPoint)
        {
            return new Point(drawingPoint.X, drawingPoint.Y);
        } 

        #endregion
    }

    #region Description of event delegates and args

    public delegate void OnXChangeEvent(object sender, XChangeEventArgs e);
    public delegate void OnYChangeEvent(object sender, YChangeEventArgs e);

    public class XChangeEventArgs : EventArgs
    {
        private int dx;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="deltaX">Value at which X changed.</param>
        public XChangeEventArgs(int deltaX)
        {
            dx = deltaX;
        }

        public int DeltaX
        {
            get { return dx; }
            set { dx = value; }
        }
    }

    public class YChangeEventArgs : EventArgs
    {
        private int dy;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="deltaY">Value at which Y changed.</param>
        public YChangeEventArgs(int deltaY)
        {
            dy = deltaY;
        }

        public int DeltaY
        {
            get { return dy; }
            set { dy = value; }
        }
    }

    #endregion
}
